#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
// We need to set this stuff up to compile for UML
#include "linux-2.6.32.8/include/linux/sched.h"
#include "linux-2.6.32.8/arch/x86/include/asm/unistd.h"
#define _NR_sys_getgcputime 337

struct sched_param {
	int sched_priority;
    int sched_group;
};

// Number of tasks per group
#define NUM_TASKS 4

int main(int argc, char **argv) {
    int i, j, rand, curr_task_cnt;
    pid_t pid;
    // First index is the group the process is in
    pid_t pid_array[5][16];

    // Set the priority of this task high so it'll spawn all of the tasks before
    // they start doing work.  Otherwise the processes that were spawned first
    // end up getting quite a bit more time relative to the processes spawned
    // later because they start doing their work first
    struct sched_param param = {
        .sched_priority = 10
    };
    pid = getpid();
    sched_setscheduler(pid, SCHED_FIFO, &param);

    // Spawn all of our processes
    for (i=0; i < 5; i++) {
        struct sched_param param = {
            .sched_priority = 1,
            .sched_group = i
        };

        //curr_task_cnt = (i + 1) * (i + 1);
        curr_task_cnt = (int) pow(2, i);
        printf("Scheduling %d tasks into group %d\n", curr_task_cnt, i);
        for (j=0; j < curr_task_cnt; j++) {
            pid = fork();
            pid_array[i][j] = pid;

            if (pid) { /* Parent Process */
                sched_setscheduler(pid, SCHED_FSG, &param); 
            }
            else { /* Child Process */
                // Do process intensive looping stuff
                int k = 0x0FFFFFFF;
                while (1) k--;
                exit(0);
            }
        }
    }
    printf("Scheduled %d processes into 5 groups.\n", NUM_TASKS);

    while(1) {
        for (i=0; i < 5; i++) {
            long time = syscall(_NR_sys_getgcputime, i);
            printf("Group %d used %ld clock ticks\n", i, time);
        }
        printf("monitor process sleeping for 5 seconds...\n");
        sleep(5);
    }

    // Wait for all of the processes to quit
    for (i=0; i < 5; i++) {
        for (j=0; j < NUM_TASKS; j++) {
            waitpid(pid_array[i][j], 0, 0);
        }
    }

    // Print stats from the syscall
    for (i=0; i < 5; i++) {
        long time = syscall(_NR_sys_getgcputime, i);
        printf("Group %d used %ld time slices\n", i, time);
    }

    return 0;
}
